<template>
  <div class="quick-sort">
    <h1 class="title">快速排序算法可视化</h1>

    <div class="algorithm-description">
      <h2 class="section-title">算法描述</h2>
      <div class="description-content">
        <p>快速排序是一种分治算法，通过选择一个'基准'元素将数组分成两个子数组，一个小于基准，一个大于基准，然后递归排序子数组。</p>
        <p><strong>算法步骤：</strong></p>
        <ol>
          <li>从数列中挑出一个元素作为基准(pivot)</li>
          <li>重新排序数列，所有比基准小的元素放在基准前面，所有比基准大的元素放在基准后面</li>
          <li>递归地对小于基准和大于基准的子数组进行排序</li>
        </ol>
        <p><strong>时间复杂度：</strong></p>
        <ul>
          <li>最坏情况：O(n²)</li>
          <li>最好情况：O(n log n)</li>
          <li>平均情况：O(n log n)</li>
        </ul>
        <p><strong>空间复杂度：</strong> O(log n) - 递归调用栈</p>
      </div>
    </div>

    <div class="control-panel">
      <el-button type="primary" @click="startSorting" :disabled="isSorting">
        <i class="el-icon-video-play"></i> {{ isSorting ? '排序中...' : '开始排序' }}
      </el-button>
      <el-button @click="pauseSorting" :disabled="!isSorting || isPaused">
        <i class="el-icon-video-pause"></i> 暂停
      </el-button>
      <el-button @click="resumeSorting" :disabled="!isPaused">
        <i class="el-icon-caret-right"></i> 继续
      </el-button>
      <el-button @click="resetArray" :disabled="isSorting && !isPaused">
        <i class="el-icon-refresh"></i> 重置
      </el-button>

      <el-slider v-model="speed" :min="100" :max="1000" :step="100" :disabled="isSorting && !isPaused"
        class="speed-slider">
        <template #prefix>
          <i class="el-icon-time"></i>
        </template>
      </el-slider>
    </div>

    <div class="visualization-container">
      <div class="array-container">
        <div v-for="(item, index) in array" :key="index" class="array-bar" :style="{
          height: item * 5 + 'px',
          backgroundColor: activeIndexes.includes(index) ? '#FF6B6B' : '#4ECDC4',
          boxShadow: activeIndexes.includes(index) ? '0 0 10px rgba(255,107,107,0.7)' : 'none'
        }">
          <span class="bar-value">{{ item }}</span>
        </div>
      </div>
    </div>

    <div class="code-section">
      <h2 class="section-title">代码实现</h2>
      <div class="code-container">
        <el-tabs type="border-card" v-model="currentLanguage">
          <el-tab-pane v-for="(_, lang) in codeLanguages" :key="lang" :label="lang" :name="lang">
            <el-button class="copy-btn" @click="copyCode" type="default" :icon="CopyDocument"></el-button>
            <pre><code>{{ codeLanguages[lang] }}</code></pre>
          </el-tab-pane>
        </el-tabs>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref } from 'vue'
import { CopyDocument } from '@element-plus/icons-vue'
import { ElMessage } from 'element-plus'

// 响应式数据
const isSorting = ref(false)
const isPaused = ref(false)
const speed = ref(500)
const sortingPromise = ref(null)
const sortingResolve = ref(null)
const array = ref([])
const activeIndexes = ref([])
const currentLanguage = ref('JavaScript')
const code = ref('')

// 代码语言定义
const codeLanguages = {
  JavaScript: `function quickSort(arr, left = 0, right = arr.length - 1) {
  if (left >= right) return arr;

  const pivotIndex = partition(arr, left, right);

  quickSort(arr, left, pivotIndex - 1);
  quickSort(arr, pivotIndex + 1, right);

  return arr;
}

function partition(arr, left, right) {
  const pivot = arr[right];
  let i = left;

  for (let j = left; j < right; j++) {
    if (arr[j] < pivot) {
      [arr[i], arr[j]] = [arr[j], arr[i]];
      i++;
    }
  }

  [arr[i], arr[right]] = [arr[right], arr[i]];
  return i;
}`,
  Java: `public class QuickSort {
  public static void quickSort(int[] arr) {
    quickSort(arr, 0, arr.length - 1);
  }

  private static void quickSort(int[] arr, int left, int right) {
    if (left >= right) return;

    int pivotIndex = partition(arr, left, right);

    quickSort(arr, left, pivotIndex - 1);
    quickSort(arr, pivotIndex + 1, right);
  }

  private static int partition(int[] arr, int left, int right) {
    int pivot = arr[right];
    int i = left;

    for (int j = left; j < right; j++) {
      if (arr[j] < pivot) {
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
        i++;
      }
    }

    arr[i] = arr[right];
    arr[right] = arr[i];
    return i;
  }
}`,
  Python: `def quick_sort(arr):
    if len(arr) <= 1:
        return arr

    pivot = arr[-1]
    left = [x for x in arr[:-1] if x < pivot]
    right = [x for x in arr[:-1] if x >= pivot]

    return quick_sort(left) + [pivot] + quick_sort(right)`,
  Golang: `func quickSort(arr []int) []int {
    if len(arr) <= 1 {
        return arr
    }

    pivot := arr[len(arr)-1]
    var left, right []int

    for i := 0; i < len(arr)-1; i++ {
        if arr[i] < pivot {
            left = append(left, arr[i])
        } else {
            right = append(right, arr[i])
        }
    }

    left = quickSort(left)
    right = quickSort(right)

    return append(append(left, pivot), right...)
}`,
  C: `void quickSort(int arr[], int left, int right) {
    if (left >= right) return;

    int pivotIndex = partition(arr, left, right);

    quickSort(arr, left, pivotIndex - 1);
    quickSort(arr, pivotIndex + 1, right);
}

int partition(int arr[], int left, int right) {
    int pivot = arr[right];
    int i = left;

    for (int j = left; j < right; j++) {
        if (arr[j] < pivot) {
            int temp = arr[i];
            arr[i] = arr[j];
            arr[j] = temp;
            i++;
        }
    }

    arr[i] = arr[right];
    arr[right] = arr[i];
    return i;
}`,
  Rust: `fn quick_sort(arr: &mut [i32]) {
    if arr.len() <= 1 {
        return;
    }

    let pivot_index = partition(arr);
    quick_sort(&mut arr[0..pivot_index]);
    quick_sort(&mut arr[pivot_index + 1..]);
}

fn partition(arr: &mut [i32]) -> usize {
    let pivot = arr[arr.len() - 1];
    let mut i = 0;

    for j in 0..arr.len() - 1 {
        if arr[j] < pivot {
            arr.swap(i, j);
            i += 1;
        }
    }

    arr.swap(i, arr.len() - 1);
    i
}`
}

// 初始化数组
const resetArray = () => {
  array.value = Array.from({ length: 10 }, () => Math.floor(Math.random() * 50) + 5)
  activeIndexes.value = []
}

// 复制代码
const copyCode = async () => {
  try {
    await navigator.clipboard.writeText(code.value)
    ElMessage.success('复制成功')
  } catch (err) {
    console.error('复制失败: ', err)
    ElMessage.error('复制失败')
  }
}

// 排序控制
const startSorting = async () => {
  if (isSorting.value) {
    return
  }

  isSorting.value = true
  isPaused.value = false
  const arr = [...array.value]

  await quickSort(arr, 0, arr.length - 1)

  activeIndexes.value = []
  isSorting.value = false
  isPaused.value = false
  sortingResolve.value = null
}

async function quickSort(arr, left, right) {
  if (left >= right) return

  const pivotIndex = await partition(arr, left, right)

  await quickSort(arr, left, pivotIndex - 1)
  await quickSort(arr, pivotIndex + 1, right)
}

async function partition(arr, left, right) {
  const pivot = arr[right]
  let i = left

  for (let j = left; j < right; j++) {
    if (isPaused.value) {
      await new Promise(resolve => {
        sortingResolve.value = resolve
      })
    }

    activeIndexes.value = [j, right]
    await new Promise(resolve => {
      sortingPromise.value = setTimeout(resolve, 1100 - speed.value)
    })

    if (arr[j] < pivot) {
      [arr[i], arr[j]] = [arr[j], arr[i]]
      i++
      array.value = [...arr]
    }
  }

  [arr[i], arr[right]] = [arr[right], arr[i]]
  array.value = [...arr]
  return i
}

const pauseSorting = () => {
  if (!isSorting.value) {
    return
  }
  isPaused.value = true
}

const resumeSorting = () => {
  if (!isPaused.value) {
    return
  }
  isPaused.value = false
  if (sortingResolve.value) {
    const resolve = sortingResolve.value
    sortingResolve.value = null
    resolve()
  } else {
    startSorting()
  }
}

// 初始化
resetArray()
</script>

<style scoped>
.quick-sort {
  --bg-color: #ffffff;
  --text-color: #333333;
  --primary-color: #409eff;
  --border-color: #dcdfe6;
  --code-bg: #f5f7fa;
  --bar-bg: #e4e7ed;
  --active-bar-bg: #f56c6c;
  max-width: 100%;
  min-height: 100vh;
  margin: 0;
  padding: 1rem;
  background-color: var(--bg-color);
  color: var(--text-color);
}

.title {
  text-align: center;
  color: var(--text-color);
  margin: 1rem 0;
  font-weight: 500;
  font-size: clamp(1.5rem, 4vw, 2rem);
}

.algorithm-description {
  background: var(--bg-color);
  border-radius: 4px;
  padding: 1rem;
  margin-bottom: 1.5rem;
  border: 1px solid var(--border-color);
}

.description-content {
  line-height: 1.6;
  font-size: clamp(0.9rem, 2vw, 1rem);
}

.control-panel {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: 0.8rem;
  margin-bottom: 1.5rem;
}

.speed-slider {
  width: clamp(150px, 30vw, 250px);
  margin-left: 0.5rem;
}

.visualization-container {
  background: var(--bg-color);
  border-radius: 4px;
  padding: 1rem;
  margin-bottom: 1.5rem;
  border: 1px solid var(--border-color);
}

.array-container {
  display: flex;
  justify-content: center;
  align-items: flex-end;
  height: 250px;
  gap: 0.3rem;
}

.array-bar {
  width: clamp(20px, 4vw, 40px);
  background: var(--bar-bg);
  border-radius: 2px 2px 0 0;
  transition: all 0.3s ease;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  align-items: center;
  border: 1px solid var(--border-color);
}

.array-bar.active {
  background: var(--active-bar-bg);
  border-color: var(--active-bar-bg);
}

.code-container {
  position: relative;
  border-radius: 4px;
  overflow: hidden;
  border: 1px solid var(--border-color);
}

.bar-value {
  margin-bottom: 5px;
  font-size: clamp(0.6rem, 1.5vw, 0.8rem);
}

.copy-btn {
  position: absolute;
  right: 10px;
  top: 10px;
  z-index: 1;
}

pre {
  overflow: auto;
}

@media (max-width: 768px) {
  .quick-sort {
    padding: 0.5rem;
  }

  .control-panel {
    gap: 0.3rem;
    flex-direction: column;
    align-items: stretch;
  }

  .array-container {
    height: 180px;
    gap: 0.2rem;
  }

  .array-bar {
    width: clamp(15px, 3vw, 25px);
  }

  .speed-slider {
    width: 100%;
    margin-left: 0;
  }

  .description-content {
    font-size: 0.8rem;
  }
}
</style>
